package org.convallaria.system.biz.service.sys.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.convallaria.system.biz.entity.SysLoginLog;
import org.convallaria.system.biz.mapper.SysLoginLogMapper;
import org.convallaria.system.biz.service.sys.SysLoginLogService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * 登录日志服务实现
 * 
 * @author convallaria
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysLoginLogServiceImpl extends ServiceImpl<SysLoginLogMapper, SysLoginLog> implements SysLoginLogService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recordLoginLog(String username, String loginIp, String loginLocation, 
                              String browser, String os, String status, String msg, Long tenantId) {
        try {
            SysLoginLog loginLog = new SysLoginLog();
            loginLog.setUserName(username);
            loginLog.setIpaddr(loginIp);
            loginLog.setLoginLocation(loginLocation);
            loginLog.setBrowser(browser);
            loginLog.setOs(os);
            loginLog.setStatus(status);
            loginLog.setMsg(msg);
            loginLog.setLoginTime(LocalDateTime.now());
            loginLog.setTenantId(tenantId);
            
            save(loginLog);
            log.info("记录登录日志成功: username={}, ip={}, status={}", username, loginIp, status);
        } catch (Exception e) {
            log.error("记录登录日志失败: username={}, ip={}", username, loginIp, e);
        }
    }

    @Override
    public IPage<SysLoginLog> getLoginLogPage(Page<SysLoginLog> page, Long userId) {
        LambdaQueryWrapper<SysLoginLog> queryWrapper = new LambdaQueryWrapper<>();
        if (userId != null) {
            queryWrapper.eq(SysLoginLog::getUserId, userId);
        }
        queryWrapper.orderByDesc(SysLoginLog::getLoginTime);
        
        return page(page, queryWrapper);
    }

    @Override
    public Long countLoginLogs(Long userId, LocalDateTime startTime, LocalDateTime endTime, String status) {
        LambdaQueryWrapper<SysLoginLog> queryWrapper = new LambdaQueryWrapper<>();
        if (userId != null) {
            queryWrapper.eq(SysLoginLog::getUserId, userId);
        }
        if (startTime != null) {
            queryWrapper.ge(SysLoginLog::getLoginTime, startTime);
        }
        if (endTime != null) {
            queryWrapper.le(SysLoginLog::getLoginTime, endTime);
        }
        if (status != null) {
            queryWrapper.eq(SysLoginLog::getStatus, status);
        }
        
        return count(queryWrapper);
    }

    @Override
    public Long countUniqueUsers(LocalDateTime startTime, LocalDateTime endTime) {
        LambdaQueryWrapper<SysLoginLog> queryWrapper = new LambdaQueryWrapper<>();
        if (startTime != null) {
            queryWrapper.ge(SysLoginLog::getLoginTime, startTime);
        }
        if (endTime != null) {
            queryWrapper.le(SysLoginLog::getLoginTime, endTime);
        }
        queryWrapper.select(SysLoginLog::getUserId)
                   .groupBy(SysLoginLog::getUserId);
        
        return count(queryWrapper);
    }

    @Override
    public Long countUniqueIps(LocalDateTime startTime, LocalDateTime endTime) {
        LambdaQueryWrapper<SysLoginLog> queryWrapper = new LambdaQueryWrapper<>();
        if (startTime != null) {
            queryWrapper.ge(SysLoginLog::getLoginTime, startTime);
        }
        if (endTime != null) {
            queryWrapper.le(SysLoginLog::getLoginTime, endTime);
        }
        queryWrapper.select(SysLoginLog::getIpaddr)
                   .groupBy(SysLoginLog::getIpaddr);
        
        return count(queryWrapper);
    }

    @Override
    public IPage<SysLoginLog> getUserLoginHistory(Long userId, Integer pageNum, Integer pageSize) {
        Page<SysLoginLog> page = new Page<>(pageNum, pageSize);
        return getLoginLogPage(page, userId);
    }
}
